package cn.itcast.bos.realm;

import java.util.List;
import java.util.Set;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import cn.itcast.bos.dao.user.UserDao;
import cn.itcast.bos.domain.auth.Function;
import cn.itcast.bos.domain.auth.Role;
import cn.itcast.bos.domain.user.User;
import cn.itcast.bos.service.auth.FunctionService;
import cn.itcast.bos.service.auth.RoleService;

public class BosRealm extends AuthorizingRealm {
	@Autowired
	private UserDao userDao;

	@Autowired
	private RoleService roleService;// 查询 角色表

	@Autowired
	private FunctionService functionService;// 查询 权限

	/**
	 * 多表联查 ??
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		// 该方法 执行 授权实现...
		System.out.println("-----授权------");
		// 权限 数据库里面 如何根据登陆用户 确认当前登陆用户是否具有 资源访问权限?
		// 1: 获取当前登陆用户 --->userId----> 多表查询 --->user_role-->role---->role_function--->权限 AuthorizationInfo perms["noticebill"]
		// 2: 获取当前登陆用户 --->userId----> 多表查询 --->user_role-->role--->AuthorizationInfo roles["base"]
		// 知识点: 1: 业务层: UserService --(多表 hql /jpql) RoleService FunctionService
		// 2: 是否要添加超级管理 接受 所有角色 和 所有 权限 对应 code 值
		// 代码是实现 超级管理员 应该具备 数据库权限表 角色 表所有 角色和 权限
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		// 获取用户信息 匹配账号
		User loginUser = (User) SecurityUtils.getSubject().getPrincipal();
		if ("admin".equals(loginUser.getUsername())) {
			// 超级管理员 查询所有角色和权限
			List<Role> roles = roleService.findAllRoles();
			for (Role role : roles) {
				info.addRole(role.getCode());// 将所有角色 code 添加SimpleAuthorizationInfo--->安全管理器
			}
			List<Function> functions = functionService.findAllFunctions();
			for (Function function : functions) {
				info.addStringPermission(function.getCode());
			}

		} else {
			// 非超级管理员 根据登陆当前用户id ---> 具有所有角色和 权限
			// 根据用id 查询 用户角色 from Role user_role
			List<Role> roles = roleService.findAllRolesByUserId(loginUser.getId());
			for (Role role : roles) {
				info.addRole(role.getCode());// 将所有角色 code 添加SimpleAuthorizationInfo--->安全管理器
				// 根据角色 获取 对应权限
				Set<Function> functions = role.getFunctions();
				for (Function function : functions) {
					info.addStringPermission(function.getCode());
				}
			}
		}
		return info;// 返回空值 没有权限...
	}

	/**
	 * 固定代码
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		// 认证实现.. AuthenticationToken token 获取 客户端输入 用户名和密码 调用dao 访问数据库
		System.out.println("---认证---");
		UsernamePasswordToken loginToke = (UsernamePasswordToken) token;
		String username = loginToke.getUsername();// 客户提交的用户
		// 通过密码校验完成 认证 系统而言 账号(唯一) 密码(可以重复) 通过账号--->密码 (数据库的密码)
		User existUser = userDao.findUserByUsername(username);
		if (existUser == null) {
			return null;
		}
		// 查询到用户存在 将数据库密码以及对象给予 AuthenticationInfo
		// 参数一 表示 existUser 参数二 数据库查询 密码 参数三 spring 配置 里面 注册该real bean id 属性名称
		// AuthenticationInfo info = new SimpleAuthenticationInfo(existUser, existUser.getPassword(), "bosrealm");
		AuthenticationInfo info = new SimpleAuthenticationInfo(existUser, existUser.getPassword(), super.getName());
		return info; // 返回控制 表示没有认证许可 认证失败 AuthenticationInfo
	}
}
